package com.zj.utils;

import com.zj.dataSource.DataSourceFactory;
import com.zj.exception.BuilderException;
import com.zj.transaction.TransactionFactory;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Properties;

public class XMLConfigBuilder {
    private boolean parsed;
    protected final Configuration cfg;
//    protected final TypeAliasRegistry typeAliasRegistry;
//    protected final TypeHandlerRegistry typeHandlerRegistry;
    private String environment;
    private Document document;


    public XMLConfigBuilder(Document document, String environment, Properties props) {
        this.cfg=new Configuration();

//        this.configuration.setVariables(props);
        this.parsed = false;
        this.environment = environment;

        this.document=document;
    }

    public Configuration parse() {
        Element root=document.getRootElement();
        if (this.parsed) {
            throw new BuilderException("Each XMLConfigBuilder can only be used once.");
        }else if(!root.getName().equals("configuration")){
            throw new BuilderException("xml can only start with configuration.");
        }else {
            this.parsed = true;
            this.parseConfiguration(root);
            return this.cfg;
        }
    }

    private void parseConfiguration(Element root) {
        try {
            parseEnvironmentsFromXML(root.element("environments"));
            parseMappersFromXML(root.element("mappers") );
        } catch (Exception var3) {
            throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3);
        }
    }

    public void parseEnvironmentsFromXML(Element child) throws Exception {
        //已知属性名情况下
        String defaultEnvironment=child.attributeValue("default");
        System.out.println("default: " + defaultEnvironment);
        List<Element> childElements = child.elements();
        if(childElements.size()==0||defaultEnvironment==null){
            throw  new Exception("Environments has not environment or default value");
        }
        for(Element child0:childElements){
            //从多个环境总选择指定的环境。
            if(defaultEnvironment.equals(child0.attributeValue("id"))){
                parseEnvironmentElement(child0);
            }
        }
    }

    public void parseEnvironmentElement(Element child ) throws Exception {
        String id=child.attributeValue("id");
        List<Element> childElements = child.elements();
        TransactionFactory txFactory=transactionManagerElement(child.element("transactionManager"));
        DataSource ds=dataSourceElement(child.element("dataSource"));
        cfg.setEnvironment(new Environment(id,txFactory,ds));

    }
    public TransactionFactory transactionManagerElement(Element child ) throws Exception{
        String type=child.attributeValue("type");
        TransactionFactory factory= (TransactionFactory)cfg.getTypeAliasRegistry().resolveAlias(type).newInstance();
        return factory;
    }

    public DataSource dataSourceElement(Element child )throws Exception{
        String type=child.attributeValue("type");
        List<Element> childElements = child.elements("property");
        Properties pro=new Properties();
        DataSourceFactory dsFactory= (DataSourceFactory)cfg.getTypeAliasRegistry().resolveAlias(type).newInstance();
        for(Element ele:childElements){
            System.out.println(ele.attributeValue("name"));
            String value=ele.attributeValue("value");
            //用此方式处理用变量取配置文件中的值（如${xxx}）的情况。
//          String value = PropertyParser.parse(attribute.getNodeValue(), this.variables);
            pro.put(ele.attributeValue("name"),value);
        }
        dsFactory.setProperties(pro);
        return dsFactory.getDataSource();
    }
    public void parseMappersFromXML(Element child ) throws Exception {
        List<Element> childElements = child.elements();
        for(Element child0:childElements){
            String resource=child0.attributeValue("resource");
            String className=child0.attributeValue("class");
            if(resource!=null&&className==null){
                InputStream inputStream = Resources.getResourceAsStream(resource);
                XMLMapperBuilder mapperParser = new XMLMapperBuilder(new SAXReader().read(inputStream), cfg, resource);
                mapperParser.parse();
            }else if(resource==null&&className!=null){
                Class<?> mapperInterface = Resources.classForName(className);
                cfg.addMapper(mapperInterface);
            }else{
                throw new BuilderException("A mapper element is not set right!");
            }
        }

    }
}
